package com.kalemao.library.custom.stateful;

import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.AnimRes;
import android.support.annotation.StringRes;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import com.kalemao.library.R;
import com.kalemao.library.custom.font.FontButton;
import com.kalemao.library.custom.font.FontTextView;
import com.kalemao.library.imageview.KLMImageView;

/**
 * Android layout to show most common state templates like loading, empty, error
 * etc. To do that all you need to is wrap the target area(view) with
 * StatefulLayout. For more information about usage look
 * <a href="https://github.com/gturedi/StatefulLayout#usage">here</a>
 */
public class StatefulLayout extends RelativeLayout {

    private static final String  MSG_ONE_CHILD        = "StatefulLayout must have one child!";
    private static final boolean DEFAULT_ANIM_ENABLED = false;
    private static final int     DEFAULT_IN_ANIM      = android.R.anim.fade_in;
    private static final int     DEFAULT_OUT_ANIM     = android.R.anim.fade_out;

    /**
     * Indicates whether to place the animation on state changes
     */
    private boolean   animationEnabled;
    /**
     * Animation started begin of state change
     */
    private Animation inAnimation;
    /**
     * Animation started end of state change
     */
    private Animation outAnimation;
    /**
     * to synchronize transition animations when animation duration shorter then
     * request of state change
     */
    private int       animCounter;

    private CustomStateOptions options;

    private View           content;
    private RelativeLayout stContainer;
    private ProgressBar    stProgress;
    private RelativeLayout stProgressLayout;
    private KLMImageView   stImage;
    private FontTextView   stMessage;
    private FontTextView   stMessageEx;
    private FontButton     stButton;

    public StatefulLayout(Context context) {
        this(context, null);
    }

    public StatefulLayout(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
        TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.stfStatefulLayout, 0, 0);
        animationEnabled = array.getBoolean(R.styleable.stfStatefulLayout_stfAnimationEnabled, DEFAULT_ANIM_ENABLED);
        inAnimation = anim(array.getResourceId(R.styleable.stfStatefulLayout_stfInAnimation, DEFAULT_IN_ANIM));
        outAnimation = anim(array.getResourceId(R.styleable.stfStatefulLayout_stfOutAnimation, DEFAULT_OUT_ANIM));
        array.recycle();
    }

    public boolean isAnimationEnabled() {
        return animationEnabled;
    }

    public void setAnimationEnabled(boolean animationEnabled) {
        this.animationEnabled = animationEnabled;
    }

    public Animation getInAnimation() {
        return inAnimation;
    }

    public void setInAnimation(Animation animation) {
        inAnimation = animation;
    }

    public void setInAnimation(@AnimRes int anim) {
        inAnimation = anim(anim);
    }

    public Animation getOutAnimation() {
        return outAnimation;
    }

    public void setOutAnimation(Animation animation) {
        outAnimation = animation;
    }

    public void setOutAnimation(@AnimRes int anim) {
        outAnimation = anim(anim);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        if (getChildCount() > 1) {
            throw new IllegalStateException(MSG_ONE_CHILD);
        }
        // hide state views in designer
        if (isInEditMode()) {
            return;
        }
        // setOrientation(VERTICAL);
        content = getChildAt(0);
        // assume first child as content
        LayoutInflater.from(getContext()).inflate(R.layout.stf_template, this, true);
        stContainer = (RelativeLayout) findViewById(R.id.stContainer);
        stProgress = (ProgressBar) findViewById(R.id.stProgress);
        stProgressLayout = (RelativeLayout) findViewById(R.id.stProgress_layout);
        stImage = (KLMImageView) findViewById(R.id.stImage);
        stMessage = (FontTextView) findViewById(R.id.stMessage);
        stMessageEx = (FontTextView) findViewById(R.id.stMessage_ex);
        stButton = (FontButton) findViewById(R.id.stButton);
    }

    // content //
    public void showContentNoAnimal() {
        stContainer.setVisibility(GONE);
        content.setVisibility(VISIBLE);
        options.setLoading(false);
    }

    public void showContent() {
        if (isAnimationEnabled()) {
            stContainer.clearAnimation();
            content.clearAnimation();
            final int animCounterCopy = ++animCounter;
            if (stContainer.getVisibility() == VISIBLE) {
                outAnimation.setAnimationListener(new CustomAnimationListener() {
                    @Override
                    public void onAnimationEnd(Animation animation) {
                        if (animCounter != animCounterCopy) {
                            return;
                        }
                        stContainer.setVisibility(GONE);
                        content.setVisibility(VISIBLE);
                        content.startAnimation(inAnimation);
                    }
                });
                stContainer.startAnimation(outAnimation);
            }
        } else {
            stContainer.setVisibility(GONE);
            content.setVisibility(VISIBLE);
        }
        options.setLoading(false);
    }

    public boolean doesShowError() {
        if (stContainer.getVisibility() == View.VISIBLE) {
            return true;
        }
        return false;
    }

    // loading //

    public void showLoading() {
        showLoading(R.string.stfLoadingMessage);
    }

    public void showLoading(@StringRes int resId) {
        showLoading(str(resId));
    }

    public void showLoading(String message) {
        showCustom(new CustomStateOptions().message(message).loading());
    }

    // empty //

    public void showEmpty() {
        showEmpty(R.string.stfEmptyMessage);
    }

    public void showEmpty(@StringRes int resId) {
        showEmpty(str(resId));
    }

    public void showEmpty(String message) {
        showCustom(new CustomStateOptions().message(message).image(R.mipmap.img_net_null));
    }

    public void showEmpty(String message, String messageEx, int imageResource) {
        showCustom(new CustomStateOptions().message(message).messageEx(messageEx).image(imageResource));
    }

    public void showEmpty(String message, String messageEx) {
        showCustom(new CustomStateOptions().message(message).messageEx(messageEx).image(R.mipmap.img_net_null));
    }

    public void showEmpty(String message, String btnMsg, OnClickListener listener) {
        showCustom(new CustomStateOptions().message(message)
                           .buttonText(btnMsg)
                           .buttonClickListener(listener)
                           .image(R.mipmap.img_net_null));
    }

    public void showEmpty(String message, String messageEx, String btnMsg, OnClickListener listener) {
        showCustom(new CustomStateOptions().message(message)
                           .buttonText(btnMsg)
                           .messageEx(messageEx)
                           .buttonClickListener(listener)
                           .image(R.mipmap.img_net_null));
    }

    public void showEmpty(String message, String messageEx, int imageResource, String btnMsg,
                          OnClickListener listener) {
        showCustom(new CustomStateOptions().message(message)
                           .buttonText(btnMsg)
                           .messageEx(messageEx)
                           .buttonClickListener(listener)
                           .image(imageResource));
    }

    // error //

    public void showError(OnClickListener clickListener) {
        showError(R.string.stfErrorMessage, clickListener);
    }

    public void showError(@StringRes int resId, OnClickListener clickListener) {
        showError(str(resId), clickListener);
    }

    public void showError(String message, OnClickListener clickListener) {
        showCustom(new CustomStateOptions().message(message)
                           .image(R.mipmap.img_net_null)
                           .buttonText(str(R.string.stfButtonText))
                           .buttonClickListener(clickListener));
    }

    // offline

    public void showOffline(OnClickListener clickListener) {
        showOffline(R.string.stfOfflineMessage, clickListener);
    }

    public void showOffline(@StringRes int resId, OnClickListener clickListener) {
        showOffline(str(resId), clickListener);
    }

    public void showOffline(String message, OnClickListener clickListener) {
        showCustom(new CustomStateOptions().message(message)
                           .image(R.mipmap.img_net_null)
                           .buttonText(str(R.string.stfButtonText))
                           .buttonClickListener(clickListener));
    }

    // location off //

    public void showLocationOff(OnClickListener clickListener) {
        showLocationOff(R.string.stfLocationOffMessage, clickListener);
    }

    public void showLocationOff(@StringRes int resId, OnClickListener clickListener) {
        showLocationOff(str(resId), clickListener);
    }

    public void showLocationOff(String message, OnClickListener clickListener) {
        showCustom(new CustomStateOptions().message(message)
                           .image(R.mipmap.img_net_null)
                           .buttonText(str(R.string.stfButtonText))
                           .buttonClickListener(clickListener));
    }

    // custom //

    /**
     * Shows custom state for given options. If you do not set
     * buttonClickListener, the button will not be shown
     *
     * @param options customization options
     */
    public void showCustom(final CustomStateOptions options) {
        this.options = options;
        if (options.isLoading()) {
            stContainer.setVisibility(VISIBLE);
            content.setVisibility(VISIBLE);
            state();
            stContainer.setBackground(getResources().getDrawable(R.drawable.no_kuang_transparent_50));
        } else if (isAnimationEnabled()) {
            stContainer.setBackground(getResources().getDrawable(R.drawable.no_kuang_white));
            stContainer.clearAnimation();
            content.clearAnimation();
            final int animCounterCopy = ++animCounter;
            if (stContainer.getVisibility() == GONE) {
                outAnimation.setAnimationListener(new CustomAnimationListener() {
                    @Override
                    public void onAnimationEnd(Animation animation) {
                        if (animCounterCopy != animCounter) {
                            return;
                        }
                        content.setVisibility(GONE);
                        stContainer.setVisibility(VISIBLE);
                        stContainer.startAnimation(inAnimation);
                    }
                });
                content.startAnimation(outAnimation);
                state();
            } else {
                outAnimation.setAnimationListener(new CustomAnimationListener() {
                    @Override
                    public void onAnimationEnd(Animation animation) {
                        if (animCounterCopy != animCounter) {
                            return;
                        }
                        state();
                        stContainer.startAnimation(inAnimation);
                    }
                });
                stContainer.startAnimation(outAnimation);
            }
        } else {
            stContainer.setBackground(getResources().getDrawable(R.drawable.no_kuang_white));
            content.setVisibility(GONE);
            stContainer.setVisibility(VISIBLE);
            state();
        }
    }

    // helper methods //

    private void state() {
        if (!TextUtils.isEmpty(options.getMessage())) {
            stMessage.setVisibility(VISIBLE);
            stMessage.setText(options.getMessage());
        } else {
            stMessage.setVisibility(GONE);
        }

        if (!TextUtils.isEmpty(options.getMessageEx())) {
            stMessageEx.setVisibility(VISIBLE);
            stMessageEx.setText(options.getMessageEx());
        } else {
            stMessageEx.setVisibility(GONE);
        }

        if (options.isLoading()) {
            stProgressLayout.setVisibility(VISIBLE);
            stImage.setVisibility(GONE);
            stButton.setVisibility(GONE);
        } else {
            stProgressLayout.setVisibility(GONE);
            if (options.getImageRes() != 0) {
                stImage.setVisibility(VISIBLE);
                stImage.setBackgroundResource(options.getImageRes());
            } else {
                stImage.setVisibility(GONE);
            }

            if (options.getClickListener() != null) {
                stButton.setVisibility(VISIBLE);
                stButton.setOnClickListener(options.getClickListener());
                if (!TextUtils.isEmpty(options.getButtonText())) {
                    stButton.setText(options.getButtonText());
                }
            } else {
                stButton.setVisibility(GONE);
            }
        }
    }

    public CustomStateOptions getOptions() {
        return options;
    }

    private String str(@StringRes int resId) {
        return getContext().getString(resId);
    }

    private Animation anim(@AnimRes int resId) {
        return AnimationUtils.loadAnimation(getContext(), resId);
    }
}
